test(ui): add UserButton connected integration test - #9191
test(ui): add UserButton connected integration test#9191alexcarpenter wants to merge 24 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🦋 Changeset detectedLatest commit: 970ea4d The changes in this PR will be included in the next version bump. This PR includes changesets to release 0 packagesWhen changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository YAML (base), Repository UI (inherited) Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
ApprovabilityVerdict: Approved This PR adds integration tests for the AccountButton component with no production code changes. The empty changeset confirms no packages are affected, making this a low-risk test-only addition. You can customize Macroscope's approvability policy. Learn more. |
Dismissing prior approval to re-evaluate 088fc5a
22e6748 to
4f890d8
Compare
b192bfc to
cb6a6fd
Compare
@clerk/astro
@clerk/backend
@clerk/chrome-extension
@clerk/clerk-js
@clerk/electron
@clerk/electron-passkeys
@clerk/eslint-plugin
@clerk/expo
@clerk/expo-google-signin
@clerk/expo-passkeys
@clerk/express
@clerk/fastify
@clerk/hono
@clerk/localizations
@clerk/nextjs
@clerk/nuxt
@clerk/react
@clerk/react-router
@clerk/shared
@clerk/tanstack-react-start
@clerk/testing
@clerk/ui
@clerk/upgrade
@clerk/vue
commit: |
API Changes Report
Summary
No API Changes DetectedAll packages have stable APIs with no detected changes. Report generated by Break Check Last ran on |
Render the connected UserButton against stubbed Clerk hooks and drive it through the popover: organization selection, account switching, sign out, accepting invitations and suggestions, single-session mode, navigation actions, busy and loading states, and the paging sentinel.
Every other action — switching account, signing out of one, joining a suggested or invited workspace — now resolves back into an open popover so the result is visible where it happened. The swingset prototypes fake the round trip they make against Clerk, so the spinner and stood-down rows are demonstrable without a running app.
The sizes track the Icon scale (sm 14px, md 16px) so a spinner can stand in for the icon it replaces, and the UserButton's trailing column is now one slot the width of the menu button, so the spinner, the active check, and the menu all sit on the same centre line.
The trigger carried the avatar alone. It now names what is active beside it — the organization and its plan wherever one heads the trigger, the account otherwise — behind `showLabel`, which defaults on. Badge's `neutral` color was unreadable in both schemes: its fill is a 900 and its text token is a text color, not an on-fill one. It now rides the same black/white scrim the button's neutral fill does.
…ccount The trigger and the popup's header now always name the same workspace. `combined` carries both switchers, so `modePriority` picks which one it leads with: the active organization by default, the account with `modePriority="user"`. Both are still listed either way.
…ser fixture The controller now reads hasOrganizations off the user resource, so the mocked user needs the field the real one has.
`setActive` swaps the active organization while its promise is still in flight, so the popup rearranged mid-action: the header renamed itself, the check jumped rows, and Invite came and went as the permission was re-read. The connected component now snapshots the controller when an action starts and renders that until it settles, so the result lands in one step. Two smaller faults fell out of the same interaction: - The spinner waited out a delay window before appearing, and the check raced ahead of it. Every action here is a network round trip, so there is nothing to debounce: `useSpinDelay` takes `delay: 0` and shows the value in the same pass, with `minDuration` still steadying it. - A row going busy swapped its host element from `<button>` to `<div>`, remounting the subtree and dropping the avatar back to its initials for the length of the action. A row that stands down now stays the button it was, disabled, and `Avatar.Image` resolves a browser-cached `src` in a layout effect so neither a remount nor a swap flashes the fallback.
The popover stayed up behind the surface it opened. Managing, inviting, creating an organization, and adding an account now close it on the way out, whether they open a modal or navigate.
The connected test drives the real controller against a mocked Clerk, which is what makes it worth having and also what makes it slow. Cases that only ever asserted what the popover renders now sit in the view test, leaving the connected one to prove the layers compose. Also covers `hidePersonal` reaching the popover through the container.
UserButtonProps picked only modePriority off the root, so the connected component was hard-wired to the combined surface and the orgs/user modes were reachable only by composing UserButtonView directly.
Presses a custom row on the connected UserButton and checks the app's callback runs and the popover closes behind it.
An instance with organizations turned off has none to lead with or list, so the button is the account's whatever `mode` asked for — `orgs` would otherwise render an empty shell of a switcher. clerk-js withholds its own OrganizationSwitcher at the mount boundary, which an app importing this one never crosses, so the gate lives in the component.
The popover's open state and the one action in flight are the same flow, so they now live in one machine instead of two useStates. Re-entry, clearing busy, and closing on success stop being hand-written in the container: RUN is simply unhandled while busy, and busy is only reachable from open. Dismissing the popover mid-action now abandons the result rather than letting it land in a surface that is already gone.
Follows the view's rename of `'orgs'` to `'organization'`. Also corrects the integration suite's opening comment, which attributed close-on-success to the container and had the navigation case backwards.
Description
Stacked on #9185. Covers the connected
UserButtonthrough the real view and the real controller against a mocked Clerk, and settles the popover behaviour that coverage exposed.One flow, one machine. The popover's open state and the one action in flight are the same flow: an action that ends the interaction closes the surface, so they settle together or not at all.
user-button.machine.tsholds both instead of twouseStates in the container. Re-entry, clearing busy, and closing on success stop being hand written there:RUNis simply unhandled while busy, and busy is only reachable from open. Dismissing the popover mid action now abandons the result rather than letting it land in a surface that is already gone.The surface holds still while an action runs. The view renders the controller the action started from.
setActiveswaps the active organization while its promise is in flight, so the live controller would otherwise rearrange the popup under the pointer: the header renaming itself, the check jumping rows, Invite coming and going as the permission is re-read. The result lands in one step when the action settles.The popover closes behind whatever it opens. A modal or another page takes over from there, so there is nothing left for the popover to show. Left up, it would sit over the very surface it just opened.
A failure leaves the popover open so the row can be clicked again. Nothing reports what went wrong yet; the error surface is its own change.
modereaches the connected button. Organizations turned off at the instance leave nothing for an organization surface to lead with or to list, so the button is the account's whatevermodeasked for. clerk-js withholds its own<OrganizationSwitcher>at the mount boundary, and nothing mounts this one, so the gate lives in the container.Checklist
pnpm testruns as expected.pnpm buildruns as expected.Type of change